/* -------- DOMAIN OPERATION HOOKS -----------*/
-static int chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
+static int _chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
{
ssidref_t chwall_ssidref;
int i, j;
traceprintk("%s.\n", __func__);
- read_lock(&acm_bin_pol_rwlock);
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)
{
printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n",
__func__);
- read_unlock(&acm_bin_pol_rwlock);
return ACM_ACCESS_DENIED; /* catching and indicating config error */
}
if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
{
printk("%s: ERROR chwall_ssidref > max(%x).\n",
__func__, chwall_bin_pol.max_ssidrefs - 1);
- read_unlock(&acm_bin_pol_rwlock);
return ACM_ACCESS_DENIED;
}
/* A: chinese wall check for conflicts */
chwall_bin_pol.max_types + i])
{
printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
- read_unlock(&acm_bin_pol_rwlock);
return ACM_ACCESS_DENIED;
}
chwall_bin_pol.max_types + j])
chwall_bin_pol.conflict_aggregate_set[j]++;
}
- read_unlock(&acm_bin_pol_rwlock);
return ACM_ACCESS_PERMITTED;
}
-static void chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
+
+static void _chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
{
int i, j;
ssidref_t chwall_ssidref;
traceprintk("%s.\n", __func__);
- read_lock(&acm_bin_pol_rwlock);
chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
/* adjust types ref-count for running domains */
for (i = 0; i < chwall_bin_pol.max_types; i++)
chwall_bin_pol.max_types + i];
if (domid)
{
- read_unlock(&acm_bin_pol_rwlock);
return;
}
/* Xen does not call pre-create hook for DOM0;
chwall_bin_pol.max_types + j])
chwall_bin_pol.conflict_aggregate_set[j]++;
}
- read_unlock(&acm_bin_pol_rwlock);
return;
}
-static void
-chwall_fail_domain_create(void *subject_ssid, ssidref_t ssidref)
-{
- int i, j;
- ssidref_t chwall_ssidref;
- traceprintk("%s.\n", __func__);
+/*
+ * To be called when creating a domain. If this call is unsuccessful,
+ * no state changes have occurred (adjustments of counters etc.). If it
+ * was successful, state was changed and can be undone using
+ * chwall_domain_destroy.
+ */
+static int chwall_domain_create(void *subject_ssid, ssidref_t ssidref,
+ domid_t domid)
+{
+ int rc;
read_lock(&acm_bin_pol_rwlock);
- chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
- /* roll-back: re-adjust conflicting types aggregate */
- for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
- {
- int common = 0;
- /* check if conflict_set_i and ssidref have common types */
- for (j = 0; j < chwall_bin_pol.max_types; j++)
- if (chwall_bin_pol.
- conflict_sets[i * chwall_bin_pol.max_types + j]
- && chwall_bin_pol.ssidrefs[chwall_ssidref *
- chwall_bin_pol.max_types + j])
- {
- common = 1;
- break;
- }
- if (common == 0)
- continue; /* try next conflict set, this one does not include any type of chwall_ssidref */
- /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
- for (j = 0; j < chwall_bin_pol.max_types; j++)
- if (chwall_bin_pol.
- conflict_sets[i * chwall_bin_pol.max_types + j]
- && !chwall_bin_pol.ssidrefs[chwall_ssidref *
- chwall_bin_pol.max_types + j])
- chwall_bin_pol.conflict_aggregate_set[j]--;
+ rc = _chwall_pre_domain_create(subject_ssid, ssidref);
+ if (rc == ACM_ACCESS_PERMITTED) {
+ _chwall_post_domain_create(domid, ssidref);
}
read_unlock(&acm_bin_pol_rwlock);
+ return rc;
}
-
-static void chwall_post_domain_destroy(void *object_ssid, domid_t id)
+/*
+ * This function undoes everything a successful call to
+ * chwall_domain_create has done.
+ */
+static void chwall_domain_destroy(void *object_ssid, struct domain *d)
{
int i, j;
struct chwall_ssid *chwall_ssidp = GET_SSIDP(ACM_CHINESE_WALL_POLICY,
.dump_statistics = chwall_dump_stats,
.dump_ssid_types = chwall_dump_ssid_types,
/* domain management control hooks */
- .pre_domain_create = chwall_pre_domain_create,
- .post_domain_create = chwall_post_domain_create,
- .fail_domain_create = chwall_fail_domain_create,
- .post_domain_destroy = chwall_post_domain_destroy,
+ .domain_create = chwall_domain_create,
+ .domain_destroy = chwall_domain_destroy,
/* event channel control hooks */
.pre_eventchannel_unbound = NULL,
.fail_eventchannel_unbound = NULL,
.dump_statistics = null_dump_stats,
.dump_ssid_types = null_dump_ssid_types,
/* domain management control hooks */
- .pre_domain_create = NULL,
- .post_domain_create = NULL,
- .fail_domain_create = NULL,
- .post_domain_destroy = NULL,
+ .domain_create = NULL,
+ .domain_destroy = NULL,
/* event channel control hooks */
.pre_eventchannel_unbound = NULL,
.fail_eventchannel_unbound = NULL,
return ACM_ACCESS_PERMITTED;
}
+static int
+ste_domain_create(void *subject_ssid, ssidref_t ssidref, domid_t domid)
+{
+ return ste_pre_domain_create(subject_ssid, ssidref);
+}
+
+
static void
-ste_post_domain_destroy(void *subject_ssid, domid_t id)
+ste_domain_destroy(void *subject_ssid, struct domain *d)
{
/* clean all cache entries for destroyed domain (might be re-used) */
- clean_id_from_cache(id);
+ clean_id_from_cache(d->domain_id);
}
/* -------- EVENTCHANNEL OPERATIONS -----------*/
.dump_ssid_types = ste_dump_ssid_types,
/* domain management control hooks */
- .pre_domain_create = ste_pre_domain_create,
- .post_domain_create = NULL,
- .fail_domain_create = NULL,
- .post_domain_destroy = ste_post_domain_destroy,
+ .domain_create = ste_domain_create,
+ .domain_destroy = ste_domain_destroy,
/* event channel control hooks */
.pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
scheduler_init();
idle_vcpu[0] = (struct vcpu*) ia64_r13;
- idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
+ idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
BUG();
expose_p2m_init();
/* Create initial domain 0. */
- dom0 = domain_create(0, 0);
+ dom0 = domain_create(0, 0, DOM0_SSIDREF);
if (dom0 == NULL)
panic("Error creating domain 0\n");
dom0_vcpu0 = alloc_vcpu(dom0, 0, 0);
scheduler_init();
/* create idle domain */
- idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
+ idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
if ((idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL))
BUG();
set_current(idle_domain->vcpu[0]);
percpu_free_unused_areas();
/* Create initial domain 0. */
- dom0 = domain_create(0, 0);
+ dom0 = domain_create(0, 0, DOM0_SSIDREF);
if (dom0 == NULL)
panic("Error creating domain 0\n");
dom0->is_privileged = 1;
- /* Post-create hook sets security label. */
- acm_post_domain0_create(dom0->domain_id);
-
cmdline = (char *)(mod[0].string ? __va((ulong)mod[0].string) : NULL);
/* scrub_heap_pages() requires IRQs enabled, and we're post IRQ setup... */
/* Domain creation requires that scheduler structures are initialised. */
scheduler_init();
- idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
+ idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
if ( (idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL) )
BUG();
acm_init(_policy_start, _policy_len);
/* Create initial domain 0. */
- dom0 = domain_create(0, 0);
+ dom0 = domain_create(0, 0, DOM0_SSIDREF);
if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) )
panic("Error creating domain 0\n");
dom0->is_privileged = 1;
- /* Post-create hook sets security label. */
- acm_post_domain0_create(dom0->domain_id);
-
/* Grab the DOM0 command line. */
cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL);
if ( cmdline != NULL )
#include <asm/debugger.h>
#include <public/sched.h>
#include <public/vcpu.h>
+#include <acm/acm_hooks.h>
/* Protect updates/reads (resp.) of domain_list and domain_hash. */
DEFINE_SPINLOCK(domlist_update_lock);
return v;
d = (vcpu_id == 0) ?
- domain_create(IDLE_DOMAIN_ID, 0) :
+ domain_create(IDLE_DOMAIN_ID, 0, 0) :
idle_vcpu[cpu_id - vcpu_id]->domain;
BUG_ON(d == NULL);
return v;
}
-struct domain *domain_create(domid_t domid, unsigned int domcr_flags)
+struct domain *domain_create(
+ domid_t domid, unsigned int domcr_flags, ssidref_t ssidref)
{
struct domain *d, **pd;
if ( grant_table_create(d) != 0 )
goto fail2;
+
+ if ( acm_domain_create(d, ssidref) != 0 )
+ goto fail3;
}
if ( arch_domain_create(d) != 0 )
- goto fail3;
+ goto fail4;
d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
d->irq_caps = rangeset_new(d, "Interrupts", 0);
if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
- goto fail4;
+ goto fail5;
if ( sched_init_domain(d) != 0 )
- goto fail4;
+ goto fail5;
if ( !is_idle_domain(d) )
{
return d;
- fail4:
+ fail5:
arch_domain_destroy(d);
+ fail4:
+ if ( !is_idle_domain(d) )
+ acm_domain_destroy(d);
fail3:
if ( !is_idle_domain(d) )
grant_table_destroy(d);
return;
}
+ acm_domain_destroy(d);
gnttab_release_mappings(d);
domain_relinquish_resources(d);
put_domain(d);
{
long ret = 0;
struct xen_domctl curop, *op = &curop;
- void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
static DEFINE_SPINLOCK(domctl_lock);
if ( !IS_PRIV(current->domain) )
if ( op->interface_version != XEN_DOMCTL_INTERFACE_VERSION )
return -EACCES;
- if ( acm_pre_domctl(op, &ssid) )
- return -EPERM;
-
spin_lock(&domctl_lock);
switch ( op->cmd )
domcr_flags |= DOMCRF_hvm;
ret = -ENOMEM;
- if ( (d = domain_create(dom, domcr_flags)) == NULL )
+ d = domain_create(dom, domcr_flags, op->u.createdomain.ssidref);
+ if ( d == NULL )
break;
ret = 0;
spin_unlock(&domctl_lock);
- if ( ret == 0 )
- acm_post_domctl(op, &ssid);
- else
- acm_fail_domctl(op, &ssid);
-
return ret;
}
int (*dump_statistics) (u8 *buffer, u16 buf_size);
int (*dump_ssid_types) (ssidref_t ssidref, u8 *buffer, u16 buf_size);
/* domain management control hooks (can be NULL) */
- int (*pre_domain_create) (void *subject_ssid, ssidref_t ssidref);
- void (*post_domain_create) (domid_t domid, ssidref_t ssidref);
- void (*fail_domain_create) (void *subject_ssid, ssidref_t ssidref);
- void (*post_domain_destroy) (void *object_ssid, domid_t id);
+ int (*domain_create) (void *subject_ssid, ssidref_t ssidref,
+ domid_t domid);
+ void (*domain_destroy) (void *object_ssid, struct domain *d);
/* event channel control hooks (can be NULL) */
int (*pre_eventchannel_unbound) (domid_t id1, domid_t id2);
void (*fail_eventchannel_unbound) (domid_t id1, domid_t id2);
# define traceprintk(fmt, args...)
#endif
+
#ifndef ACM_SECURITY
-static inline int acm_pre_domctl(struct xen_domctl *op, void **ssid)
-{ return 0; }
-static inline void acm_post_domctl(struct xen_domctl *op, void *ssid)
-{ return; }
-static inline void acm_fail_domctl(struct xen_domctl *op, void *ssid)
-{ return; }
static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
{ return 0; }
static inline int acm_pre_eventchannel_interdomain(domid_t id)
{ return 0; }
static inline int acm_is_policy(char *buf, unsigned long len)
{ return 0; }
-static inline void acm_post_domain0_create(domid_t domid)
-{ return; }
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
{ return 0; }
+static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
+{ return 0; }
+static inline void acm_domain_destroy(struct domain *d)
+{ return; }
-#else
-
-static inline int acm_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
-{
- if ((acm_primary_ops->pre_domain_create != NULL) &&
- acm_primary_ops->pre_domain_create(subject_ssid, ssidref))
- return ACM_ACCESS_DENIED;
- else if ((acm_secondary_ops->pre_domain_create != NULL) &&
- acm_secondary_ops->pre_domain_create(subject_ssid, ssidref)) {
- /* roll-back primary */
- if (acm_primary_ops->fail_domain_create != NULL)
- acm_primary_ops->fail_domain_create(subject_ssid, ssidref);
- return ACM_ACCESS_DENIED;
- } else
- return ACM_ACCESS_PERMITTED;
-}
-
-static inline void acm_post_domain_create(domid_t domid, ssidref_t ssidref)
-{
- if (acm_primary_ops->post_domain_create != NULL)
- acm_primary_ops->post_domain_create(domid, ssidref);
- if (acm_secondary_ops->post_domain_create != NULL)
- acm_secondary_ops->post_domain_create(domid, ssidref);
-}
+#define DOM0_SSIDREF 0x0
-static inline void acm_fail_domain_create(
- void *subject_ssid, ssidref_t ssidref)
-{
- if (acm_primary_ops->fail_domain_create != NULL)
- acm_primary_ops->fail_domain_create(subject_ssid, ssidref);
- if (acm_secondary_ops->fail_domain_create != NULL)
- acm_secondary_ops->fail_domain_create(subject_ssid, ssidref);
-}
+#else
-static inline void acm_post_domain_destroy(void *object_ssid, domid_t id)
-{
- if (acm_primary_ops->post_domain_destroy != NULL)
- acm_primary_ops->post_domain_destroy(object_ssid, id);
- if (acm_secondary_ops->post_domain_destroy != NULL)
- acm_secondary_ops->post_domain_destroy(object_ssid, id);
- return;
-}
static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
{
return ACM_ACCESS_PERMITTED;
}
-static inline int acm_pre_domctl(struct xen_domctl *op, void **ssid)
-{
- int ret = -EACCES;
- struct domain *d;
-
- switch(op->cmd) {
- case XEN_DOMCTL_createdomain:
- ret = acm_pre_domain_create(
- current->domain->ssid, op->u.createdomain.ssidref);
- break;
- case XEN_DOMCTL_destroydomain:
- if (*ssid != NULL) {
- printkd("%s: Warning. Overlapping destruction.\n",
- __func__);
- return -EACCES;
- }
- d = rcu_lock_domain_by_id(op->domain);
- if (d != NULL) {
- *ssid = d->ssid; /* save for post destroy when d is gone */
- if (*ssid == NULL) {
- printk("%s: Warning. Destroying domain without ssid pointer.\n",
- __func__);
- rcu_unlock_domain(d);
- return -EACCES;
- }
- d->ssid = NULL; /* make sure it's not used any more */
- /* no policy-specific hook */
- rcu_unlock_domain(d);
- ret = 0;
- }
- break;
- default:
- ret = 0; /* ok */
- }
- return ret;
-}
-
-static inline void acm_post_domctl(struct xen_domctl *op, void **ssid)
-{
- switch(op->cmd) {
- case XEN_DOMCTL_createdomain:
- /* initialialize shared sHype security labels for new domain */
- acm_init_domain_ssid(
- op->domain, op->u.createdomain.ssidref);
- acm_post_domain_create(
- op->domain, op->u.createdomain.ssidref);
- break;
- case XEN_DOMCTL_destroydomain:
- if (*ssid == NULL) {
- printkd("%s: ERROR. SSID unset.\n",
- __func__);
- break;
- }
- acm_post_domain_destroy(*ssid, op->domain);
- /* free security ssid for the destroyed domain (also if null policy */
- acm_free_domain_ssid((struct acm_ssid_domain *)(*ssid));
- *ssid = NULL;
- break;
- }
-}
-
-static inline void acm_fail_domctl(struct xen_domctl *op, void **ssid)
-{
- switch(op->cmd) {
- case XEN_DOMCTL_createdomain:
- acm_fail_domain_create(
- current->domain->ssid, op->u.createdomain.ssidref);
- break;
- case XEN_DOMCTL_destroydomain:
- /* we don't handle domain destroy failure but at least free the ssid */
- if (*ssid == NULL) {
- printkd("%s: ERROR. SSID unset.\n",
- __func__);
- break;
- }
- acm_free_domain_ssid((struct acm_ssid_domain *)(*ssid));
- *ssid = NULL;
- }
-}
static inline int acm_pre_grant_map_ref(domid_t id)
{
}
}
-static inline void acm_post_domain0_create(domid_t domid)
+
+static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
{
- /* initialialize shared sHype security labels for new domain */
- int dom0_ssidref = dom0_ste_ssidref << 16 | dom0_chwall_ssidref;
+ void *subject_ssid = current->domain->ssid;
+ domid_t domid = d->domain_id;
+ int rc;
+
+ /*
+ To be called when a domain is created; returns '0' if the
+ domain is allowed to be created, != '0' if not.
+ */
+ rc = acm_init_domain_ssid_new(d, ssidref);
+ if (rc != ACM_OK)
+ return rc;
- acm_init_domain_ssid(domid, dom0_ssidref);
- acm_post_domain_create(domid, dom0_ssidref);
+ if ((acm_primary_ops->domain_create != NULL) &&
+ acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
+ return ACM_ACCESS_DENIED;
+ } else if ((acm_secondary_ops->domain_create != NULL) &&
+ acm_secondary_ops->domain_create(subject_ssid, ssidref,
+ domid)) {
+ /* roll-back primary */
+ if (acm_primary_ops->domain_destroy != NULL)
+ acm_primary_ops->domain_destroy(d->ssid, d);
+ acm_free_domain_ssid(d->ssid);
+ return ACM_ACCESS_DENIED;
+ }
+
+ return 0;
+}
+
+
+static inline void acm_domain_destroy(struct domain *d)
+{
+ void *ssid = d->ssid;
+ if (ssid != NULL) {
+ if (acm_primary_ops->domain_destroy != NULL)
+ acm_primary_ops->domain_destroy(ssid, d);
+ if (acm_secondary_ops->domain_destroy != NULL)
+ acm_secondary_ops->domain_destroy(ssid, d);
+ /* free security ssid for the destroyed domain (also if null policy */
+ acm_free_domain_ssid((struct acm_ssid_domain *)(ssid));
+ }
}
+
static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
{
if ((acm_primary_ops->sharing != NULL) &&
/* Return true iff buffer has an acm policy magic number. */
extern int acm_is_policy(char *buf, unsigned long len);
+#define DOM0_SSIDREF (dom0_ste_ssidref << 16 | dom0_chwall_ssidref)
+
#endif
#endif
#include <public/xen.h>
#include <public/domctl.h>
#include <public/vcpu.h>
+#include <public/acm.h>
#include <xen/time.h>
#include <xen/timer.h>
#include <xen/grant_table.h>
return d;
}
-struct domain *domain_create(domid_t domid, unsigned int domcr_flags);
+struct domain *domain_create(
+ domid_t domid, unsigned int domcr_flags, ssidref_t ssidref);
/* DOMCRF_hvm: Create an HVM domain, as opposed to a PV domain. */
#define _DOMCRF_hvm 0
#define DOMCRF_hvm (1U<<_DOMCRF_hvm)